﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Device.Location;
using System.Diagnostics;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using Microsoft.Phone.Controls.Maps.Core;

namespace Coding4Fun.WheresMyCar
{
    public partial class MapSet : PhoneApplicationPage, INotifyPropertyChanged
    {
		private const double MetersPerPixel = 156543.04; // meters/pixel for base map

        private Map _map;
        private GeoCoordinateWatcher _gps;
		private Shape _circle;
        private MapLayer _circleLayer;
		private bool _locationSet;

        public MapSet()
        {
            InitializeComponent();

			Settings = WheresTheCarSettings.Instance;
			DataContext = this;
		
            if (Utility.IsCoordNullOrUnknown(CurrentLocation))
            {
                this.CurrentLocation = IsolatedStorageSettings.ApplicationSettings["location"] as GeoCoordinate;
                this.MapCenter = this.CurrentLocation;
            }

            if (_map == null)
			{
				_map = Utility.CreateMap();
				_map.MapZoom += _map_MapZoom;
				_map.SetBinding(MapBase.CenterProperty, new Binding {Path = new PropertyPath("MapCenter"), Mode = BindingMode.TwoWay});
				_circle = new Ellipse
				{
					Stroke = new SolidColorBrush(Colors.LightGray),
					StrokeThickness = 2,
					Fill = (SolidColorBrush)Resources["PhoneAccentBrush"],
					Opacity = .4
				};

				_circle.SetBinding(MapLayer.PositionProperty, new Binding("CurrentLocation"));

				_circleLayer = new MapLayer();
				_map.Children.Add(_circleLayer);

				MapGrid.Children.Add(_map);
			}

			_gps = ((App)Application.Current).GPS;
			_gps.StatusChanged += GpsStatusChanged;
			_gps.PositionChanged += GpsPositionChanged;

			if (_gps.Position != null)
				GpsPositionChanged(this, null);
        }

		void _map_MapZoom(object sender, MapZoomEventArgs e)
		{
			UpdateAccuracyCircle();
		}

		private void UpdateAccuracyCircle()
		{
			Dispatcher.BeginInvoke(() =>
			                       	{
			                       		if (_circleLayer.Children.Contains(_circle))
			                       			_circleLayer.Children.Remove(_circle);

			                       		// http://msdn.microsoft.com/en-us/library/aa940990.aspx
			                       		var resolution = MetersPerPixel*Math.Cos(CurrentLocation.Latitude*Math.PI/180.0)/
			                       		                 Math.Pow(2.0, _map.ZoomLevel);
			                       		Accuracy = Math.Round(_gps.Position.Location.HorizontalAccuracy, 0);
			                       		var diameter = Accuracy/resolution;

										if (diameter < 50)
											diameter = 50;

			                       		_circle.Width = diameter;
			                       		_circle.Height = diameter;
			                       		_circleLayer.AddChild(_circle, CurrentLocation, PositionOrigin.Center);

			                       		// Only show the accuracy indicator if accuracy is higher than 3km,
			                       		// the circle is within the size of the screen
			                       		_circle.Visibility = (Accuracy <= 3000 && diameter < ActualWidth
			                       		                      	? Visibility.Visible
			                       		                      	: Visibility.Collapsed);
			                       	});
		}

    	#region Public Properties
        private WheresTheCarSettings _settings;
        public WheresTheCarSettings Settings
        {
            get { return _settings; }
            set
            {
                _settings = value;
                RaisePropertyChanged("Settings");
            }
        }

		#region Accuracy (INotifyPropertyChanged Property)
		private double _accuracy;

		public double Accuracy
		{
			get { return _accuracy; }
			set
			{
				_accuracy = value;
				RaisePropertyChanged("Accuracy");
			}
		}
		#endregion

        #region MapCenter (INotifyPropertyChanged Property)
        private GeoCoordinate _mapCenter;

        public GeoCoordinate MapCenter
        {
            get { return _mapCenter; }
            set
            {
                _mapCenter = value;
                RaisePropertyChanged("MapCenter");
            }
        }
        #endregion

        #region CurrentLocation (INotifyPropertyChanged Property)
        private GeoCoordinate _currentLocation;
        public GeoCoordinate CurrentLocation
        {
            get { return _currentLocation; }
            set
            {
                _currentLocation = value;
                RaisePropertyChanged("CurrentLocation");
            }
        }
        #endregion
        #endregion

        #region Event Handlers
        void GpsStatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            if (e.Status == GeoPositionStatus.Ready)
            {
                GpsPositionChanged(this, null);
            }
        }

        void GpsPositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            if (!Utility.IsCoordNullOrUnknown(_gps.Position.Location))
            {
                this.CurrentLocation = _gps.Position.Location;
				if(!_locationSet)
					this.MapCenter = this.CurrentLocation;
				
				_locationSet = true;
				UpdateAccuracyCircle();
            }
        }

        private void ApplicationBarIconButton_Click(object sender, EventArgs e)
        {
            Settings.ParkingSpot = this.MapCenter;
            this.Settings.Save();
            Utility.SaveControlBitmap(_map, "map.jpg");
            NavigationService.GoBack();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (!Utility.IsCoordNullOrUnknown(Settings.ParkingSpot))
                this.MapCenter = Settings.ParkingSpot;
            else if (!Utility.IsCoordNullOrUnknown(this.CurrentLocation))
                this.MapCenter = this.CurrentLocation;
        }
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

		protected void RaisePropertyChanged(string propertyName)
		{
			Dispatcher.BeginInvoke(() =>
			{
				if (PropertyChanged != null)
				{
					PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
				}
			});
		}
		#endregion

    }
}